﻿using System.Runtime.CompilerServices;
using System.Timers;
using Microsoft.Extensions.Logging;
using Timer = System.Timers.Timer;

namespace Devonline.Communication.Abstractions;

/// <summary>
/// 通讯客户端
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class Communicator<T> : ICommunicator<T>
{
    #region 内部成员
    protected const string LOG_COMMUNICATOR = "Communicator {communicator}";
    protected readonly ILogger<Communicator<T>> _logger;
    protected readonly ICommunicatorOptions _options;
    protected readonly Timer _timer;
    protected readonly EventArgs _defaultEventArgs = new();
    #endregion

    /// <summary>
    /// 运行状态
    /// </summary>
    public virtual bool IsRunning { get; protected set; }
    /// <summary>
    /// 连接状态
    /// </summary>
    public virtual bool IsConnected { get; protected set; }

    #region 事件
    /// <summary>
    /// 初始化事件处理方法
    /// </summary>
    public event EventHandler<ICommunicatorOptions>? Initial;
    /// <summary>
    /// 当连接服务器过程中执行的事件委托, 发生于刚发起连接请求时, 以及断线重连时
    /// </summary>
    public event EventHandler? Connecting;
    /// <summary>
    /// 当和服务器建立连接时执行的事件委托
    /// </summary>
    public event EventHandler? Connected;
    /// <summary>
    /// 通讯间隔监控触发时执行的事件处理委托方法
    /// </summary>
    public event EventHandler? Monitor;
    /// <summary>
    /// 当通讯结束(包括连接终止/强制终止)时执行的事件委托
    /// </summary>
    public event EventHandler? Abort;
    /// <summary>
    /// 当客户端收到消息时执行的事件委托
    /// </summary>
    public event EventHandler<T>? Receive;
    /// <summary>
    /// 通讯出现错误时执行的事件处理委托方法
    /// </summary>
    public event EventHandler<Exception>? Error;
    #endregion

    public Communicator(ILogger<Communicator<T>> logger, ICommunicatorOptions options)
    {
        _logger = logger;
        _options = options;
        _timer = new Timer(options.MonitorInterval * AppSettings.UNIT_THOUSAND)
        {
            Enabled = true,
            AutoReset = true
        };
    }

    #region 公开调用的控制方法
    /// <summary>
    /// 启动通讯器
    /// </summary>
    public virtual async Task StartAsync()
    {
        try
        {
            _logger.LogWarning(LOG_COMMUNICATOR + " startup", _options);

            IsRunning = true;

            OnInitial();

            //启动监听
            _timer.Elapsed += OnMonitor;
            _timer.Start();

            await OnStartAsync();
        }
        catch (Exception ex)
        {
            OnError(ex);
        }
    }
    /// <summary>
    /// 关闭通讯器
    /// </summary>
    public virtual async Task StopAsync()
    {
        try
        {
            IsRunning = false;
            _timer.Stop();
            _timer.Elapsed -= OnMonitor;
            _timer.Dispose();
            _logger.LogWarning(LOG_COMMUNICATOR + " has been stoped", _options.Communicator);
            await Task.Run(() => Abort?.Invoke(this, _defaultEventArgs));
        }
        catch (Exception ex)
        {
            OnError(ex);
        }
    }
    /// <summary>
    /// 暂停通讯
    /// </summary>
    public virtual void Pause()
    {
        IsRunning = false;
        _timer.Stop();
        _logger.LogWarning(LOG_COMMUNICATOR + " was paused", _options);
    }
    /// <summary>
    /// 继续通讯
    /// </summary>
    public virtual void Continue()
    {
        _logger.LogWarning(LOG_COMMUNICATOR + " will continue", _options);
        IsRunning = true;
        _timer.Start();
    }
    /// <summary>
    /// 发送数据到默认接收者
    /// 此处的数据对象可以接受 IEnumerable<T> 集合数据, 及 PagedResult<T> 传递分页的数据
    /// </summary>
    /// <param name="t">待发送的数据</param>
    /// <returns></returns>
    public abstract Task SendAsync(T t);
    #endregion

    #region 内部实现的基础方法
    /// <summary>
    /// 打开通讯器的具体方法, 需要子类实现
    /// 此方法只能未异步方式因为有些通讯类型只提供异步连接
    /// </summary>
    protected abstract Task OpenAsync();
    /// <summary>
    /// 通讯器初始化
    /// </summary>
    protected virtual void OnInitial()
    {
        try
        {
            //初始化
            _logger.LogInformation(LOG_COMMUNICATOR + " initial", _options);
            if (!IsConnected)
            {
                Initial?.Invoke(this, _options);
            }
        }
        catch (Exception ex)
        {
            OnError(ex);
        }
    }
    /// <summary>
    /// 打开通讯器启动通讯
    /// </summary>
    /// <exception cref="Exception"></exception>
    protected virtual async Task OnStartAsync()
    {
        try
        {
            //启动通讯器
            OnConnecting();
            await OpenAsync();
            if (IsConnected)
            {
                _logger.LogWarning(LOG_COMMUNICATOR + " open success!", _options);
                OnConnected();
            }
            else
            {
                _logger.LogError(LOG_COMMUNICATOR + " open failed!", _options);
            }
        }
        catch (Exception ex)
        {
            OnError(ex);
        }
    }
    /// <summary>
    /// 当链接关闭时执行的事件处理委托方法
    /// </summary>
    /// <param name="exception"></param>
    /// <returns></returns>
    protected virtual void OnConnecting()
    {
        if (!IsRunning)
        {
            return;
        }

        //连接前
        if (!IsConnected)
        {
            try
            {
                _logger.LogInformation(LOG_COMMUNICATOR + " is connecting", _options);
                Connecting?.Invoke(this, _defaultEventArgs);
            }
            catch (Exception ex)
            {
                OnError(ex);
            }
        }
    }
    /// <summary>
    /// 当建立连接时执行的事件处理委托
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    protected virtual void OnConnected()
    {
        if (!IsRunning)
        {
            return;
        }

        //连接后
        if (IsConnected)
        {
            try
            {
                _logger.LogInformation(LOG_COMMUNICATOR + " was connected", _options);
                Connected?.Invoke(this, _defaultEventArgs);
            }
            catch (Exception ex)
            {
                OnError(ex);
            }
        }
    }
    /// <summary>
    /// 接收数据的方法
    /// </summary>
    /// <param name="t">接收的数据</param>
    protected virtual void OnReceive(T t)
    {
        try
        {
            _logger.LogDebug(LOG_COMMUNICATOR + " recevied the data: {data}", _options, t);
            Receive?.Invoke(this, t);
        }
        catch (Exception ex)
        {
            OnError(ex);
        }
    }
    /// <summary>
    /// 错误处理方法
    /// </summary>
    /// <param name="exception"></param>
    /// <param name="memberName"></param>
    protected virtual void OnError(Exception exception, [CallerMemberName] string memberName = "")
    {
        _logger.LogError(exception, LOG_COMMUNICATOR + " {action} throw exception", _options, memberName);
        Error?.Invoke(this, exception);
    }
    /// <summary>
    /// 客户端连接监控
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="args"></param>
    private async void OnMonitor(object? sender, ElapsedEventArgs args)
    {
        if (IsRunning)
        {
            try
            {
                _logger.LogDebug(LOG_COMMUNICATOR + " current running state is: {isRunning}, and connection state is: {isConnected}", _options, IsRunning, IsConnected);

                if (!IsConnected)
                {
                    await OnStartAsync();
                }

                Monitor?.Invoke(this, args);
            }
            catch (Exception ex)
            {
                OnError(ex);
            }
        }
    }
    #endregion
}